// ===============================================================================
// scan: sequential scan of a large descriptor collection
// Created in September 2007 as a project for an Advanced Database Systems course
// (c) Reykjavik University, Björn Þór Jónsson, Kristleifur Daðason, Herwig Lejsek
// Contact author: Björn Þór Jónsson, Reykjavík University, bjorn@ru.is
// ===============================================================================

#include "IndexMapper.h"

IndexMapper::IndexMapper(ConfigMapper *cnfg)
{
	cnfgMapper = cnfg;

	// Open the file
	string filename = cnfgMapper->getIndxPath();
	indxFile = fopen(filename.c_str(), "rb");
	if (errno != 0) 	{
		cout << "IndexMapper (" << filename << ")" << endl;
		cout << "fopen error: " << errno << ": " << strerror(errno) << endl;
		exit(0);
	}

	// Get the size of each entry and the number of clusters
	struct stat filestat;
	fstat(fileno(indxFile), &filestat);
	fileSize = filestat.st_size;
	indexEntrySize = getIndexEntryByteSize(cnfgMapper->getNumDims());
	numClusters = fileSize / indexEntrySize;

	// Map the file into memory
	//mapPtr = (unsigned char *) mmap(0, filestat.st_size, PROT_READ, MAP_SHARED, fileno(indxFile), 0); 
	mapPtr = (unsigned char*) malloc(fileSize);
	fread(mapPtr, fileSize, 1, indxFile); 
	if (errno != 0) {
		cout << "errno: " << errno << ", message: " << strerror(errno) << endl;
		numClusters = 0;
	}

	// Open the data file
	filename = cnfgMapper->getDataPath();
	dataFile = fopen(filename.c_str(), "rb");
	if (errno != 0) 	{
		cout << "IndexMapper (" << filename << ")" << endl;
		cout << "fopen error: " << errno << ": " << strerror(errno) << endl;
		exit(0);
	}
};

IndexMapper::~IndexMapper()
{
	free(mapPtr);
	fclose(indxFile);
	fclose(dataFile);
}

int IndexMapper::getNumClusters()
{
	return numClusters;
}

FlexDescriptor *IndexMapper::getCentroid(int i)
{
	/*
	off_t offset = i * indexEntrySize;
	IndexEntry *entry = (IndexEntry *)(mapPtr + offset);
	return (FlexDescriptor *)&(entry->centroid);
	*/
	off_t offset = i * indexEntrySize;
	// So Indexentry contains a Flexdescriptor as well, where the int id of the 
	// Flexdescriptor is the cluster id. The offset must thus be calculated and 
	// then account for the three ints of IndexEntry, offset, pages and size.
	return (FlexDescriptor *)(mapPtr + offset + sizeof(IndexEntry));
}

ClusterMapper *IndexMapper::getCluster(int i)
{
	off_t offset = i * indexEntrySize;
	IndexEntry *entry = (IndexEntry *)(mapPtr + offset);
	return new ClusterMapper(cnfgMapper, entry, dataFile);
}
